/*
std::async   std::future创建后台任务并返回值
有时候我们希望利用一个线程的返回值，此时我们可以通过全局变量或者指针的方式把线程
的操作结果带回，同时我们可以使用以上两个函数模板把线程的值代回

std：：async是一个函数模板，用来启动一个异步任务，启动任务之后，他还会返回
一个std：：future对象

启动异步任务：自动创建一个线程并开始执行对应的线程入口函数，返回一个future对象

std：：future同样是一个类模板他含有线程入口函数的返回结果，可以利用他的get（）
方法进行读取

有人也称future提供了一种访问异步操作结果的机制，就是所这个结果我们可能无法
立即拿到但是在将来线程执行完毕后我们可以得到结果

可以理解为future保存一个值，这个值在将来某个时刻可以拿到

future对象的的成员方法：
get（）等待并取得线程的返回值
只能调用一次get（），因为底层是move实现的


wait（）只等待

如果不写wait（）或者get（），线程也会等待输出
可能是内部再析构时调用了wait（）
最好是手动等待线程结束

我们可以向saync（）额外传递一个参数，该参数是一个std：：lunch类型（枚举类型）
来表示一些不同执行
a.std：：lunch：：deferred表示线程入口函数调用被延迟到std：：future的wait（）
	或get（）函数调用时才执行
	如果wait（）或get（）没有被调用，那么线程会执行吗？
	不会执行，甚至没有创建线程
	（主线程id与子线程id相同，代表没有子线程）
std：：lunch：：deferred延迟调用，并且没有创建新线程，是在主线程调用的线程入口函数

std：：lunch：：async表示在调用async时就创建新线程
	不要等到get（）或wait，线程就自动创建并启动起来
	这个是默认参数

如果两个参数同时传入即lunch：：async|lunch：：deferred则会按照deferred处理
（顺序无关）



std：：packaged-task：打包任务，把任务包装起来
是一个类模板，他的模板参数是各种可调用对象，通过packaged-task把可调用对象打包
方便将来入口函数的调用

另外packaged-task也是一个可调用对象


std::promise类模板
我们可以在某个线程中给他赋值，在其他线程中取出来
使用：作为函数参数传递
总结：通过promise保存一个值，再与future绑定后，通过future取出	



什么时候用：不能为了用而用，最终可以实现目的，并且稳定高效即可



*/




#include<iostream>
#include<future>
#include<list>
#include<string>
#include<mutex>
#include<thread>
#include<map>	

using namespace std;

//类的成员函数做线程的入口函数
class A {

public:
	int mythread(int mypar) {

		//打印传入的参数
		cout << mypar << endl;
		//打印线程id
		cout << "mythread() start	   " << "threadid" << this_thread::get_id() << endl;
		//停留5秒
		chrono::milliseconds dura(5000);
		this_thread::sleep_for(dura);
		//打印新线程id
		cout << "mythread() end	   " << "threadid" << this_thread::get_id() << endl;
		//返回值
		return 5;



	}
};


////线程入口函数
//int mythread(int mypar) {
//
//	//打印传入的参数
//	cout << mypar << endl;
//	//打印线程id
//	cout << "mythread() start	   " << "threadid" << this_thread::get_id() << endl;
//	//停留5秒
//	chrono::milliseconds dura(5000);
//	this_thread::sleep_for(dura);
//	//打印新线程id
//	cout << "mythread() end	   " << "threadid" << this_thread::get_id() << endl;
//	//返回值
//	return 5;
//}

void mythread(promise<int>& tempp, int calc) {
	//做一些复杂计算
	calc++;
	calc *= 10;
	//做其他计算，一共花费了5秒中
	chrono::milliseconds dura(5000);
	this_thread::sleep_for(dura);

	//计算出结果，并保存
	//set_value()方法
	int result = calc;
	tempp.set_value(result);

}


void mythread2(future<int>& tmpf) {
	auto result = tmpf.get();
	cout << "thread 2 result=" << result << endl;
	return;
}



int main(int argc, char* argv[]) {
	////打印主线程id
	//cout << "main" << "threadID" << this_thread::get_id() << endl;
	//定义函数模板		|创建线程并指定执行线程函数
	//这句代码使future对象result和mythread线程绑定在了一起
	//可以在末尾的参数传入值作为函数的入口函数的参数
	//future<int> result = async(mythread);

	//类成员函数做入口函数
	//A a;
	//int temppar = 12;
	//第一个是入口函数
	//第二个参数是类对象的引用（用引用传入可以不让程序再次创建对象）
	// 他的作用相对于入口函数的this指针参数（表明这个入口函数属于谁）
	//第三个参数是入口函数的括号内的参数
	//future<int> result = async(&A::mythread, &a, temppar);

	//传入launch参数
	//future<int> result = async(launch::deferred,&A::mythread, &a, temppar);

	//cout << "continue......!" << endl;
	//int def = 0;
	////打印子线程的返回值
	////get()会等待result拿到那个值
	//cout << result.get() << endl;
	//	cout << "I love china" << endl;


	//包装函数，注意<>内的写法<函数返回值（参数，参数。。。）>
	//packaged_task<int(int)>mypt(mythread);
	////包装lambda表达式
	//packaged_task<int(int)>mypt([](int mypar) {
	//	//打印传入的参数
	//	cout << mypar << endl;
	//	//打印线程id
	//	cout << "mythread() start	   " << "threadid" << this_thread::get_id() << endl;
	//	//停留5秒
	//	chrono::milliseconds dura(5000);
	//	this_thread::sleep_for(dura);
	//	//打印新线程id
	//	cout << "mythread() end	   " << "threadid" << this_thread::get_id() << endl;
	//	//返回值
	//	return 5; 
	//	});

	////直接调用task对象
	//packaged_task<int(int)>mypt(mythread);
	////相对于函数调用，不会创建新线程
	//mypt(100);

	////容器插入,用移动语句而不是直接复制到容器
	////移动之后myty被置空
	//vector < packaged_task<int(int)>> mytasks;
	//mytasks.push_back(move(mypt));
	////取出packaged
	//packaged_task<int(int)>mypt2;
	//auto iter = mytasks.begin();
	////移动而不是复制，把容器此处的下标移动，但是没有删除此下标出的空间
	//mypt2 = move(*iter);
	////删除了第一个元素迭代器已经失效，后续代码不能再用iter
	//mytasks.erase(iter);

	////ref()让参数按照引用传递 ，mypt的引用，
	////1是入口函数的参数
	//thread t1(ref(mypt),1);
	//t1.join();
	////绑定future对象和mypt的包装函数
	////取得包装函数返回值
	////get_future()成员函数
	//future<int> result = mypt.get_future();
	//cout << result.get() << endl;
	//cout << "Main end" << endl;


	//声明promise对象保存值的类型为int
	promise<int> mypromise;
	//参数：1线程入口函数2赋值引用3函数参数
	thread t1(mythread, ref(mypromise), 180);
	t1.join();

	//获取值,绑定future和promise对象
	future<int> ful = mypromise.get_future();
	//int result = ful.get();
	//cout << result << endl;


	//线程间通信
	//把第一个线程的结果传入第二个线程
	//创建线程2并等待其运行完毕
	thread t2(mythread2, ref(ful));
	t2.join();

	return 0;
	

}